package top.huiwow.listeners;

import org.bukkit.*;
import org.bukkit.entity.*;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerPickupItemEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.Vector;
import top.huiwow.GameCore;
import top.huiwow.entity.Negromancer;
import top.huiwow.entity.Nicron;
import top.huiwow.managers.GamePlayer;
import top.huiwow.utils.*;

import java.util.HashMap;

public class PlayerListener implements Listener {
    public static HashMap<Player, Boolean> canfire = new HashMap<>();
    GameCore plugin;

    public PlayerListener() {
        plugin = GameCore.getInstance();
    }



    @EventHandler
    public void onJoin(PlayerJoinEvent e) {
        e.getPlayer().setMaxHealth(200);
        e.getPlayer().setHealth(200);
    }

    @EventHandler
    public void onRespawn(PlayerRespawnEvent e) {
        e.getPlayer().setMaxHealth(200);
        e.getPlayer().setHealth(200);
    }

    @EventHandler
    public void onHit(EntityDamageByEntityEvent e) {
        GamePlayer damager = Validates.validateP(e);
        if (damager == null) {
            return;
        }

        if (e.getCause().equals(EntityDamageEvent.DamageCause.ENTITY_ATTACK) || e.getCause().equals(EntityDamageEvent.DamageCause.PROJECTILE)) {
            double baseDamage;
            ItemStack inHand = damager.getPlayer().getItemInHand();
            if (ItemBuilder.isRPGItem(inHand) && ItemBuilder.getStatsModifier(inHand).getDamage() != 0) {
                baseDamage = ItemBuilder.getStatsModifier(inHand).getDamage();
            } else {
                baseDamage = 1;
            }

            e.setDamage(DamageCalculator.calculateNormalAttack(baseDamage, damager.getStrength(), damager.getCritChance(), damager.getCritDamage()));

        }

    }

    @EventHandler
    public void onDamaged(EntityDamageByEntityEvent e) {
        LivingEntity damager = Validates.validateE(e);
        if (damager == null) {
            return;
        }
        Player victim = ((Player) e.getEntity());
        if (e.getDamager() instanceof WitherSkull
        /*
          There should be a metadata check soon because different withers have different damage...
         */
        ) {
            //modified wither skull
            e.setDamage(10);
        }
        if (EntityListener.isEntity(damager, GameCore.getInstance().getEntityManager().getInternalID(Negromancer.class))) {
            //negromancer
            e.setDamage(4);
        }
        //defense calculation here
        int defense = plugin.getGamePlayerManager().get(victim.getUniqueId()).getDefense();
        float reduction = 1 - (defense / (defense + 100f));
        e.setDamage(e.getDamage() * reduction);
    }

    @EventHandler(priority = EventPriority.HIGHEST)
    public void preventSelfDMG(EntityDamageByEntityEvent e) {
        Entity dmger;
        if (e.getDamager() instanceof Projectile && ((Projectile) e.getDamager()).getShooter() instanceof Entity) {
            dmger = (Entity) ((Projectile) e.getDamager()).getShooter();
        } else {
            dmger = e.getDamager();
        }
        if (dmger != null) {
            if ((dmger instanceof Player && e.getEntity() instanceof Player) || (!(dmger instanceof Player) && !(e.getEntity() instanceof Player))) {
                e.setCancelled(true);
            }
        }
    }


    @EventHandler
    public void onClick(PlayerInteractEvent e) {
        if (e.getItem() == null) return;
        if (e.getItem().getType().equals(Material.BOW)) {
            if (ItemBuilder.isItem(e.getItem(), "term")) {
                termClick(e.getPlayer());
            }
        }

    }

    private void termClick(Player player) {
        if (!canfire.containsKey(player)) {
            canfire.put(player, true);
        }
        Arrow a1;
        Arrow a2;
        Arrow a3;
        if (canfire.get(player)) {
            canfire.put(player, false);
            a1 = player.launchProjectile(Arrow.class);
            a1.setVelocity(a1.getVelocity().multiply(2.5));
            a1.setMetadata(GameCore.getMetadataValue(), GameCore.getFixedMetadataValue());

            a2 = player.launchProjectile(Arrow.class);

            a2.setCustomName("terminator");
            a2.setVelocity(rotateVector(a1.getVelocity(), 50.38));
            a2.setMetadata(GameCore.getMetadataValue(), GameCore.getFixedMetadataValue());

            a3 = player.launchProjectile(Arrow.class);

            a3.setCustomName("terminator");
            a3.setMetadata(GameCore.getMetadataValue(), GameCore.getFixedMetadataValue());
            player.playSound(player.getLocation(), Sound.SHOOT_ARROW, 1, 1);
            a3.setVelocity(rotateVector(a1.getVelocity(), -50.38));
            new BukkitRunnable() {
                @Override
                public void run() {
                    if (a1.isValid()) {
                        a1.remove();
                    }
                    if (a2.isValid()) {
                        a2.remove();
                    }
                    if (a3.isValid()) {
                        a3.remove();
                    }
                }
            }.runTaskLater(plugin, 300);
            new BukkitRunnable() {
                @Override
                public void run() {
                    canfire.put(player, true);
                }
            }.runTaskLater(plugin, 3);

        }
    }

    public Vector rotateVector(Vector vector, double whatAngle) {
        double cos = Math.cos(whatAngle);
        double sin = Math.sin(whatAngle);
        double x = vector.getX() * cos + vector.getZ() * sin;
        double z = vector.getX() * -sin + vector.getZ() * cos;

        return vector.setX(x).setZ(z);
    }

    //ANTI PICKUP
    @EventHandler
    public void onPlayerPickupItem(final PlayerPickupItemEvent e) {
        if (e.getItem().hasMetadata(GameCore.getMetadataValue())) {
            e.setCancelled(true);
        }
    }

    @EventHandler
    public void onArrowDamage(EntityDamageByEntityEvent e) {
        if (!(e.getEntity() instanceof LivingEntity)) return;
        if (!(e.getDamager() instanceof Arrow)) return;
        Arrow arrow = (Arrow) e.getDamager();
        if (!(arrow.getShooter() instanceof Player)) return;
        Player player = (Player) arrow.getShooter();

        player.playSound(player.getLocation(), Sound.SUCCESSFUL_HIT, 1, 0);
    }
}
